/**
 * External Agent System
 * Manages discovery, loading, and instantiation of external agents from CCPM and SuperClaude projects
 */

import { promises as fs } from 'fs';
import { join, extname } from 'path';
import { BaseAgent, AgentContext, AgentResult } from './base-agent.js';
import { MCPBridgedAgent } from './mcp-bridged-agent.js';

export interface ExternalAgentInfo {
  name: string;
  path: string;
  source: 'ccpm' | 'superclaude';
  metadata: ExternalAgentMetadata;
  content: string;
}

export interface ExternalAgentMetadata {
  description?: string;
  tools?: string[];
  model?: string;
  color?: string;
  category?: string;
}

export class ExternalAgentSystem {
  private agents: Map<string, MCPBridgedAgent> = new Map();
  private agentInfos: Map<string, ExternalAgentInfo> = new Map();
  private initialized: boolean = false;

  async initialize(): Promise<void> {
    if (this.initialized) return;

    try {
      // Get environment paths
      const ccpmPath = process.env.CCPM_PATH || '/Users/mac/work/github/merge/ccpm';
      const superclaudePath = process.env.SUPERCLAUDE_PATH || '/Users/mac/work/github/merge/SuperClaude_Framework';

      // Discover CCPM agents
      await this.discoverCCPMAgents(ccpmPath);

      // Discover SuperClaude agents
      await this.discoverSuperClaudeAgents(superclaudePath);

      // Create bridged agent instances
      await this.createBridgedAgents();

      this.initialized = true;
      console.log(`[ExternalAgentSystem] Initialized ${this.agents.size} external agents`);
    } catch (error: any) {
      console.error('[ExternalAgentSystem] Initialization failed:', error.message);
      throw new Error(`Failed to initialize external agent system: ${error.message}`);
    }
  }

  private async discoverCCPMAgents(ccpmPath: string): Promise<void> {
    try {
      const agentsDir = join(ccpmPath, '.claude', 'agents');
      const files = await fs.readdir(agentsDir);

      for (const file of files) {
        if (extname(file) === '.md') {
          const agentName = file.replace('.md', '');
          const filePath = join(agentsDir, file);

          try {
            const content = await fs.readFile(filePath, 'utf-8');
            const metadata = this.parseCCPMMetadata(content);

            const agentInfo: ExternalAgentInfo = {
              name: agentName,
              path: filePath,
              source: 'ccpm',
              metadata,
              content
            };

            this.agentInfos.set(agentName, agentInfo);
            console.log(`[ExternalAgentSystem] Discovered CCPM agent: ${agentName}`);
          } catch (error: any) {
            console.warn(`[ExternalAgentSystem] Failed to load CCPM agent ${agentName}:`, error.message);
          }
        }
      }
    } catch (error: any) {
      console.warn(`[ExternalAgentSystem] CCPM agents directory not accessible: ${error.message}`);
    }
  }

  private async discoverSuperClaudeAgents(superclaudePath: string): Promise<void> {
    try {
      const agentsDir = join(superclaudePath, 'SuperClaude', 'Agents');
      const files = await fs.readdir(agentsDir);

      for (const file of files) {
        if (extname(file) === '.md') {
          const agentName = file.replace('.md', '');
          const filePath = join(agentsDir, file);

          try {
            const content = await fs.readFile(filePath, 'utf-8');
            const metadata = this.parseSuperClaudeMetadata(content);

            const agentInfo: ExternalAgentInfo = {
              name: agentName,
              path: filePath,
              source: 'superclaude',
              metadata,
              content
            };

            this.agentInfos.set(agentName, agentInfo);
            console.log(`[ExternalAgentSystem] Discovered SuperClaude agent: ${agentName}`);
          } catch (error: any) {
            console.warn(`[ExternalAgentSystem] Failed to load SuperClaude agent ${agentName}:`, error.message);
          }
        }
      }
    } catch (error: any) {
      console.warn(`[ExternalAgentSystem] SuperClaude agents directory not accessible: ${error.message}`);
    }
  }

  private parseCCPMMetadata(content: string): ExternalAgentMetadata {
    const metadata: ExternalAgentMetadata = {};

    // Parse YAML frontmatter for CCPM agents
    const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
    if (frontmatterMatch) {
      const frontmatter = frontmatterMatch[1];

      // Parse key-value pairs
      const lines = frontmatter.split('\n');
      for (const line of lines) {
        const match = line.match(/^(\w+):\s*(.+)$/);
        if (match) {
          const [, key, value] = match;
          switch (key) {
            case 'description':
              metadata.description = value;
              break;
            case 'tools':
              metadata.tools = value.split(',').map(t => t.trim());
              break;
            case 'model':
              metadata.model = value;
              break;
            case 'color':
              metadata.color = value;
              break;
          }
        }
      }
    }

    return metadata;
  }

  private parseSuperClaudeMetadata(content: string): ExternalAgentMetadata {
    const metadata: ExternalAgentMetadata = {};

    // Parse YAML frontmatter for SuperClaude agents
    const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
    if (frontmatterMatch) {
      const frontmatter = frontmatterMatch[1];

      // Parse key-value pairs
      const lines = frontmatter.split('\n');
      for (const line of lines) {
        const match = line.match(/^(\w+):\s*(.+)$/);
        if (match) {
          const [, key, value] = match;
          switch (key) {
            case 'description':
              metadata.description = value;
              break;
            case 'category':
              metadata.category = value;
              break;
          }
        }
      }
    }

    return metadata;
  }

  private async createBridgedAgents(): Promise<void> {
    for (const [name, agentInfo] of this.agentInfos) {
      try {
        const bridgedAgent = new MCPBridgedAgent(name, agentInfo);
        this.agents.set(name, bridgedAgent);
      } catch (error: any) {
        console.warn(`[ExternalAgentSystem] Failed to create bridged agent ${name}:`, error.message);
      }
    }
  }

  getAgent(name: string): MCPBridgedAgent | null {
    return this.agents.get(name) || null;
  }

  getAvailableAgentNames(): string[] {
    return Array.from(this.agents.keys());
  }

  getAgentInfo(name: string): ExternalAgentInfo | null {
    return this.agentInfos.get(name) || null;
  }

  getAllAgentInfos(): ExternalAgentInfo[] {
    return Array.from(this.agentInfos.values());
  }

  hasAgent(name: string): boolean {
    return this.agents.has(name);
  }

  getAgentsBySource(source: 'ccpm' | 'superclaude'): ExternalAgentInfo[] {
    return Array.from(this.agentInfos.values()).filter(info => info.source === source);
  }

  getAgentsByCategory(category: string): ExternalAgentInfo[] {
    return Array.from(this.agentInfos.values()).filter(info =>
      info.metadata.category === category
    );
  }

  getAgentCapabilities(name: string): string[] {
    const agentInfo = this.agentInfos.get(name);
    if (!agentInfo) return [];

    const capabilities: string[] = [];

    // Add tools as capabilities
    if (agentInfo.metadata.tools) {
      capabilities.push(...agentInfo.metadata.tools);
    }

    // Add category as capability
    if (agentInfo.metadata.category) {
      capabilities.push(agentInfo.metadata.category);
    }

    // Parse content for capabilities
    const content = agentInfo.content.toLowerCase();

    // Common capability keywords
    const keywords = [
      'test', 'testing', 'backend', 'frontend', 'api', 'database',
      'security', 'performance', 'quality', 'analysis', 'debug',
      'deploy', 'build', 'refactor', 'parallel', 'coordinate'
    ];

    for (const keyword of keywords) {
      if (content.includes(keyword)) {
        capabilities.push(keyword);
      }
    }

    return [...new Set(capabilities)]; // Remove duplicates
  }

  async refreshAgents(): Promise<void> {
    this.agents.clear();
    this.agentInfos.clear();
    this.initialized = false;
    await this.initialize();
  }

  getStats(): {
    total: number;
    ccpm: number;
    superclaude: number;
    categories: Record<string, number>;
  } {
    const total = this.agentInfos.size;
    let ccpm = 0;
    let superclaude = 0;
    const categories: Record<string, number> = {};

    for (const agentInfo of this.agentInfos.values()) {
      if (agentInfo.source === 'ccpm') ccpm++;
      if (agentInfo.source === 'superclaude') superclaude++;

      if (agentInfo.metadata.category) {
        categories[agentInfo.metadata.category] = (categories[agentInfo.metadata.category] || 0) + 1;
      }
    }

    return { total, ccpm, superclaude, categories };
  }
}